﻿using System;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Web.Http;
using Sustainalytics.Insights.Service.Dto;
using Sustainalytics.Utils;
using Sustainalytics.AwsS3.Client;
using System.Web.Http.Cors;
using Sustainalytics.Utils.Serilog;

namespace Sustainalytics.Insights.Service
{
    [EnableCors(origins: "*", headers: "*", methods: "*")]
    //[AutoInvalidateCacheOutput]
    [RoutePrefix("api/v1/files")]
    public class FilesController : ApiController, IFileController
    {
        private readonly string baseUrl;
        private readonly IS3Client _s3Client;
        private readonly string _s3FolderName;
        private readonly string _s3BucketName;

        public FilesController(IS3Client s3Client)
        {
            _s3Client = s3Client;

            this.baseUrl = ConfigurationManager.AppSettings["ClientPlatformUrl"];
            this._s3FolderName = ConfigurationManager.AppSettings["S3FolderName"];
            this._s3BucketName = ConfigurationManager.AppSettings["S3BucketName"];
        }

        [HttpGet]
        // [CacheOutput(ServerTimeSpan = 100, ClientTimeSpan = 0, NoCache = true, MustRevalidate = true, Private = true)]
        [Route("{id}")]
        public virtual HttpResponseMessage Get([FromUri] string id)
        {
            try
            {
                var result = Request.CreateResponse(HttpStatusCode.OK);

                var fileContent = _s3Client.DownloadFile(_s3BucketName, string.Format("{0}/{1}", _s3FolderName, id));
                if (fileContent != null)
                {
                    string mimeType = null;
                    var ext = Path.GetExtension(id);
                    switch (ext)
                    {
                        case ".pdf":
                            mimeType = "application/pdf";
                            break;
                        case ".jpg":
                        case ".jpeg":
                            mimeType = "application/jpeg";
                            break;
                        case ".png":
                            mimeType = "application/png";
                            break;
                    }

                    result.Content = new PushStreamContent((outStream, httpContent, context) =>
                    {
                        using (var ms = new MemoryStream(fileContent))
                        {
                            ms.CopyTo(outStream);
                        }
                        outStream.Close();
                    });

                    var fileName = string.Empty;
                    if (id != null)
                    {
                        var fileS3NameSplit = id.Split(new[] { '_' }, 2);
                        if (fileS3NameSplit.Length > 1)
                            fileName = fileS3NameSplit[1];
                    }

                    result.Content.Headers.Add("Content-Disposition", "attachement; filename=" + Uri.EscapeDataString(fileName));
                    result.Content.Headers.ContentType = new MediaTypeHeaderValue(mimeType);
                    return result;
                }
                return Request.CreateResponse(HttpStatusCode.NotFound);
            }
            catch (Exception ex)
            {
                return Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message);
            }
        }

        [HttpPost]

        public virtual Task<HttpResponseMessage> Post()
        {
            Guid id = Guid.Empty;
            try
            {
                id = Guid.NewGuid();
                string fileName = Request.Content.Headers.ContentDisposition.FileName.Replace(@"\", string.Empty).Replace("\"", string.Empty);
                var fileUrl = InsightDto.ComposeFileUrl(id, baseUrl);

                var result = Request.Content.ReadAsByteArrayAsync().ContinueWith(task =>
                {
                    if (task.IsCanceled || task.IsFaulted)
                        throw new HttpRequestException();

                    var bucketName = _s3BucketName;
                    var key = string.Format("{0}/{1}_{2}", _s3FolderName, id.ToString(), fileName);
                    var fileBytes = task.Result.ToArray();

                    _s3Client.UploadFile(bucketName, key, fileBytes);

                    return Request.CreateResponse(HttpStatusCode.OK, new { fileUrl = fileUrl, id = id, S3Name = string.Format("{0}_{1}", id.ToString(), fileName) });
                });

                return result;
            }
            catch (Exception ex)
            {
                return (new Task<HttpResponseMessage>(() => Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message)));
            }
        }


        [HttpPut]
        [Route("{id}")]
        public virtual Task<HttpResponseMessage> Put([FromUri] Guid id)
        {
            Guid newId = Guid.Empty;
            try
            {
                //todo - delete file from S3 by id

                newId = Guid.NewGuid();
                string fileName = Request.Content.Headers.ContentDisposition.FileName.Replace(@"\", string.Empty).Replace("\"", string.Empty);

                var fileUrl = InsightDto.ComposeFileUrl(newId, baseUrl);

                var result = Request.Content.ReadAsByteArrayAsync().ContinueWith(task =>
                {
                    if (task.IsCanceled || task.IsFaulted)
                        throw new HttpRequestException();

                    var bucketName = _s3BucketName;
                    var key = string.Format("{0}/{1}_{2}", _s3FolderName, newId.ToString(), fileName);
                    var fileBytes = task.Result.ToArray();

                    _s3Client.UploadFile(bucketName, key, fileBytes);

                    return Request.CreateResponse(HttpStatusCode.OK, new { fileUrl = fileUrl, id = newId, S3Name = string.Format("{0}_{1}", newId.ToString(), fileName) });
                });

                return result;
            }
            catch (Exception ex)
            {
                return (new Task<HttpResponseMessage>(() => Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message)));
            }
        }

    }
}

